Skip to content

ENH: Auto-compute ITK_VERSION_TWEAK from git commit date (supersedes #6667)#6676

Open
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:enh-tweak-version-git-count
Open

ENH: Auto-compute ITK_VERSION_TWEAK from git commit date (supersedes #6667)#6676
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:enh-tweak-version-git-count

Conversation

@hjmjohnson

@hjmjohnson hjmjohnson commented Jul 21, 2026

Copy link
Copy Markdown
Member

Auto-computes ITK_VERSION_TWEAK at configure time as the YYYYMMDD date of the most recent commit, replacing the hand-edited date file of #6667. Addresses @blowekamp's request that the tweak be "automatically determined from the last commit on the main branch or similarly" and uses the .git_archival.txt / setuptools-scm mechanism he pointed to for tarball reliability.

The computation is pure CMake — a native build gains no interpreter dependency.

Supersedes #6667. Only one of the two should merge.

How it works

CMake/itkVersionTweak.cmake (included right after project()) resolves the date in this order, then sets ITK_VERSION_TWEAK / ITK_VERSION_FULL:

  1. .git_archival.txt first, so an archive — or a fork that commits a substituted file — pins the date it declares. The file is only accepted when its node-date is actually substituted, so this repository's committed $Format:$ placeholder is ignored.
  2. git log -1 --format=%cd --date=short in a working tree. Unlike git describe, this succeeds in a shallow or tagless clone.
  3. 0 when neither is available.

.gitattributes marks .git_archival.txt as export-subst and overrides the blanket .git* export-ignore so the file actually ships in git archive tarballs.

ITK_VERSION_TWEAK and ITK_VERSION_FULL are exported through ITKConfig.cmake; ITKConfigVersion.cmake gains a four-component PACKAGE_VERSION while still matching three-component find_package(ITK 6.0.0 EXACT) requests.

No manual file edits are ever required — the tweak advances with every commit.

Resolution order, verified
Source tree Result
Working tree (placeholder unsubstituted) git log → today's date
git archive tarball, no .git substituted node-date → same date
Fork with a committed substituted archival, .git present archival wins → pinned date
Shallow / tagless clone (--depth 1 --no-tags) git log → same date
No git and no archival 0
ccache safety

The changing date must never trigger a full rebuild. It reaches only ITKConfig.cmake (a downstream find_package artifact, not compiled). The compiled itkConfigure.h keeps MAJOR/MINOR/PATCH and ITK_VERSION_STRING = "6.0" — verified to contain no tweak — so recomputing the tweak on reconfigure does not invalidate any translation unit.

Caveats

Per @blowekamp's review refinement, switching from commit count to commit date removes the shallow-clone caveat entirely — the date survives --depth 1 --no-tags, and is also carried by .git_archival.txt. What remains:

  1. Two commits on the same day share a tweak. Day granularity, not commit granularity. Downstream gating on ITK_VERSION_FULL distinguishes days, not individual commits.
  2. The date is not a total order across branches, and history rewriting can change it. As noted in review, the versioning is intended to be meaningful on main and release branches only.
  3. A plain (non-git archive) tarball with no .git still reports 0.
Local validation
  • All five resolution paths in the table above exercised via cmake -P against real and synthesized trees, including a genuine git clone --depth 1 --no-tags (resolves to the commit date, not 0).
  • ITKConfigVersion matching with a YYYYMMDD tweak: 6.0.0→exact, four-component exact→exact, older date→compatible, newer date→incompatible, 5.4.0→compatible.
  • Compiled itkConfigure.h.in contains no TWEAK / VERSION_FULL.
  • pre-commit run --all-files clean.
Relative to #6667

#6667 required a maintainer to run BumpVersionTweak.py and commit CMake/itkVersion.cmake on every migration/API change, with a YYYYMMDD value. This PR produces the same YYYYMMDD shape automatically, removing that manual burden entirely, and drops the associated AGENTS.md / git-commits.md policy text. The known tarball failure mode is handled by .git_archival.txt rather than accepted. The unrelated "Python 3.11 wrapped floor" migration note that #6667 accumulated during triage is intentionally left out of this focused PR.

@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Enhancement Improvement of existing methods or implementation area:Python wrapping Python bindings for a class area:Documentation Issues affecting the Documentation module labels Jul 21, 2026
@thewtex
thewtex requested a review from blowekamp July 21, 2026 18:47
@hjmjohnson
hjmjohnson marked this pull request as ready for review July 21, 2026 21:30
@greptile-apps

This comment was marked as resolved.

Comment thread Utilities/Maintenance/ComputeVersionTweak.py Outdated
@hjmjohnson
hjmjohnson force-pushed the enh-tweak-version-git-count branch from 382f3cc to 812b6a7 Compare July 21, 2026 22:11

@blowekamp blowekamp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the implementation I was suggesting.

The "ComputeVersionTweak" script should be implemented in CMake and not python to avoid a core ITK build dependency on modern Python.

Also consider how forked versions of ITK can manage this upstream version. It may be beneficial to have a git_archival.txt file take priority over the git repo information. This way a fork could commit the archive file from when the forked occurred? There may be other ways to support upstream versioning and forked versioning, but additional consideration is needed.

Are there other caveats to this approach?

Comment thread Utilities/Maintenance/ComputeVersionTweak.py Outdated
@hjmjohnson
hjmjohnson force-pushed the enh-tweak-version-git-count branch 2 times, most recently from 928f59d to c6b9100 Compare July 22, 2026 15:03
@github-actions github-actions Bot removed the area:Python wrapping Python bindings for a class label Jul 22, 2026
@hjmjohnson

Copy link
Copy Markdown
Member Author

Reworked in c6b9100. Two force-pushes: the first (812b6a78b4d928f59d6363) is a plain rebase on main, the second (928f59d6363c6b9100d09c) is this review's changes only.

Python dependency removed. ComputeVersionTweak.py is deleted and the whole computation is CMake. You were right that my earlier reply conflated two things — the 3.11 floor is the wrapped-Python floor, and a native C++ build should not acquire an interpreter dependency at all. It no longer has one.

.git_archival.txt now takes priority over the git repo, as you suggested. It is read first; the file is only accepted if its describe-name is actually substituted, so upstream's committed $Format:$ placeholder is ignored and a working tree falls through to git describe. A fork that commits a substituted file gets exactly the behavior you described — it pins the upstream count from the fork point, and its own commits do not advance it.

Verified resolution order
Source tree Result
Working tree (placeholder unsubstituted) git describe → 6090 (matches v6.0b02-6090-g812b6a78b4d)
git archive tarball, no .git substituted archival → 6090
Fork with a committed substituted archival, .git present archival wins → pinned count
Exactly on a tag 0
No git and no archival 0
Shallow / tagless clone 0

Full ITK reconfigure: ITKConfig.cmakeITK_VERSION_TWEAK "6090", ITKConfigVersion.cmakePACKAGE_VERSION "6.0.0.6090". find_package matching still behaves: 6.0.0 exact, 6.0.0.6090 exact, older tweak compatible, newer incompatible. itkConfigure.h contains no tweak (ITK_VERSION_STRING "6.0"), so ccache is unaffected.

Other caveats — the ones I think are real, stated plainly rather than buried:

  1. Shallow and tagless clones report 0. git clone --depth 1 (and --no-tags) has no reachable tag, so git describe fails and the tweak is 0. This degrades quietly rather than failing the configure, but it means CI using shallow clones publishes 6.0.0.0. This is the most likely way to get a surprising value in practice.
  2. The count is not a total order across branches. Two branches the same distance from a tag get the same tweak, so ITK_VERSION_FULL orders commits only within a linear history. Downstream gating on it is reliable against released tags, not between topic branches.
  3. History rewriting changes it. A rebase or squash-merge changes the commit count, so the same logical change can carry different tweaks before and after landing.
  4. It depends on the v[0-9]* tag convention being maintained and on tags being fetched.

Happy to take (1) further — e.g. warning at configure time when the tweak resolves to 0 in something that looks like a git checkout — if you think that is worth the noise.

@hjmjohnson

Copy link
Copy Markdown
Member Author

@blowekamp The fixup based on your request has been completed.

@blowekamp

Copy link
Copy Markdown
Member

Other caveats — the ones I think are real, stated plainly rather than buried:

  1. Shallow and tagless clones report 0. git clone --depth 1 (and --no-tags) has no reachable tag, so git describe fails and the tweak is 0. This degrades quietly rather than failing the configure, but it means CI using shallow clones publishes 6.0.0.0. This is the most likely way to get a surprising value in practice.
  2. The count is not a total order across branches. Two branches the same distance from a tag get the same tweak, so ITK_VERSION_FULL orders commits only within a linear history. Downstream gating on it is reliable against released tags, not between topic branches.
  3. History rewriting changes it. A rebase or squash-merge changes the commit count, so the same logical change can carry different tweaks before and after landing.
  4. It depends on the v[0-9]* tag convention being maintained and on tags being fetched.

Caveat #1 would not occur with the earlier suggested DATE method. The date of the last commit should still be in the .git_archive.txt file and the shallow commits. ( Note: when referencing SimpleITK I did not mean to suggest switching to the method of number of commits in SimpelTK).

Regarding caveat #2 and #3, the versioning would only be "valid" for release and main branches.

I think either method can work, it is just a matter of accepting and mitigating the limitation of such an automatic versioning system.

Set the fourth (tweak) version component at configure time to the YYYYMMDD
date of the most recent commit, instead of a hand-edited date. The
computation is pure CMake, so a native build gains no interpreter
dependency: `.git_archival.txt` is read first, so an exported tarball --
or a fork that commits a substituted file -- pins the date it declares,
and a working tree falls through to `git log`, which succeeds even in a
shallow or tagless clone.

ITK_VERSION_TWEAK and ITK_VERSION_FULL are exported through
ITKConfig.cmake for downstream between-tag gating. The value never reaches
itkConfigure.h, so the daily change cannot invalidate ccache.

Supersedes the manual-file approach of InsightSoftwareConsortium#6667.

Co-Authored-By: Bradley Lowekamp <321061+blowekamp@users.noreply.github.com>
@hjmjohnson
hjmjohnson force-pushed the enh-tweak-version-git-count branch from c6b9100 to 2e2c3bd Compare July 22, 2026 17:44
@hjmjohnson hjmjohnson changed the title ENH: Auto-compute ITK_VERSION_TWEAK from git commit count (supersedes #6667) ENH: Auto-compute ITK_VERSION_TWEAK from git commit date (supersedes #6667) Jul 22, 2026
@hjmjohnson

Copy link
Copy Markdown
Member Author

Thank you — that's the right refinement, and it makes the whole thing better. Swapped to the date method in 2e2c3bd0ad (that force-push is this change only).

You were right that caveat #1 was self-inflicted. git log -1 --format=%cd --date=short succeeds where git describe fails, so a git clone --depth 1 --no-tags now resolves to the real commit date instead of quietly publishing 6.0.0.0. And as you noted, node-date is already in .git_archival.txt, so tarballs are covered by the same field the archive substitution was going to carry anyway. Thanks also for the clarification that the SimpleITK reference was about the file mechanism, not about adopting commit counts — I over-read it.

The resolution order and the fork-pinning behavior you asked for are unchanged; only the value's provenance moved:

Source tree Result
Working tree git log → commit date
git archive tarball, no .git substituted node-date → same date
Fork with a committed substituted archival archival wins → pinned date
Shallow / tagless clone git log → same date (previously 0)
No git and no archival 0

Still pure CMake, and the tweak still reaches only ITKConfig.cmakeitkConfigure.h has no TWEAK, so ccache is unaffected. find_package matching verified with a YYYYMMDD tweak: three-component exact still matches, older date compatible, newer date incompatible.

Agreed on your framing for the remaining limitations: the version is meaningful on main and release branches, and topic-branch ordering isn't something this should try to solve. The one genuinely new trade-off versus the count is granularity — two commits landing the same day share a tweak. For gating downstream baselines against released tags that seems clearly acceptable, but say the word if you'd rather have finer resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Documentation Issues affecting the Documentation module type:Enhancement Improvement of existing methods or implementation type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants